#include "copyright.h"

#include "syscall.h"
#include "TicketClerk.h"


void finishedAgent(const char* name, int length){

	if(GetMonitor(ManagerFinishedName, ManagerFinishedNameLength, 0) == 1){
		ReleaseLock(name, length);
		Exit(1);
	}

}



int ticketClerkInitialize(){

	int myIndex;
	
	AcquireLock(ticketClerkIndexLockName, ticketClerkIndexLockNameLength);
		myIndex = GetMonitor(nextTicketClerkName, nextTicketClerkNameLength,0);
		SetMonitor(nextTicketClerkName, nextTicketClerkNameLength, myIndex + 1,0);
	ReleaseLock(ticketClerkIndexLockName, ticketClerkIndexLockNameLength);

	SetMonitor(ticketClerkLineCountName, ticketClerkLineCountNameLength, 0, myIndex);
	SetMonitor(ticketClerkStateName, ticketClerkStateNameLength, -1, myIndex);
				
	return myIndex;

}

void ticketClerk(){

	int myIndex;
	int tmp;
	
	myIndex = ticketClerkInitialize();
	


	while(1){ /* while true */
		/*Printing("TicketClerk %i\n", ConsoleOutput, myIndex, 0);*/
		/*Printing("ticketClerk %i acquiring lock &i\n", ConsoleOutput, myIndex, ticketClerkLineLock);*/
		AcquireLock(ticketClerkLineLockName, ticketClerkLineLockNameLength); /* Lock for choosing a line */
		/*printf("\tTC%i: line length:%i\n", myIndex, ticketClerkLineCount[myIndex]);*/
		/* check if there is a customer in my line */
		if(GetMonitor(ticketClerkLineCountName,ticketClerkLineCountNameLength,myIndex) > 0){ /* There is someone in my line */
			/*printf("\tTC%i: Someone is in my line!\n", myIndex);*/
			/* Steps
			1. set my state to busy
			2. decrement line count
			3. wake up 1 customer */
			
			Printing("TicketClerk %i has a line length %i and is signaling a customer.\n", ConsoleOutput, myIndex, GetMonitor(ticketClerkLineCountName,ticketClerkLineCountNameLength,myIndex));
			SetMonitor(ticketClerkStateName, ticketClerkStateNameLength, 1, myIndex); /* state = BUSY */
			SetMonitor(ticketClerkLineCountName,ticketClerkLineCountNameLength,GetMonitor(ticketClerkLineCountName,ticketClerkLineCountNameLength,myIndex) - 1,myIndex);
			 /* decrement line count */
			Signal(ticketClerkLineConditionVariableName[myIndex], ticketClerkLineConditionVariableNameLength[myIndex], ticketClerkLineLockName, ticketClerkLineLockNameLength);
		} else { /* no one is in my line */
			/* Steps
			1. set my state to not_busy */
			
			/*printf("\tTC%i: No one is in my line D:\n", myIndex);*/
			Printing("TicketClerk %i has no one in line. I am available for a customer.\n", ConsoleOutput, myIndex, 0);
			SetMonitor(ticketClerkStateName, ticketClerkStateNameLength, 0, myIndex);
			/* state = NOT_BUSY */
		}
		
		/* done with clerks first monitor.
		   clerk is ready to wait
		   by acquiring the next lock before releasing the current lock,
		   we guarantee that we get the lock first */		
		AcquireLock(ticketClerkLockName[myIndex], ticketClerkLockNameLength[myIndex]);
		/*printf("\tTC%i: releasing line lock and starting interaction\n", myIndex);*/
		ReleaseLock(ticketClerkLineLockName, ticketClerkLineLockNameLength);
		
		/*STEP 1: TicketClerk-Customer, Waiting for the customer to come up to ticket window so it can begin.*/		
		Wait(ticketClerkConditionVariableName[myIndex], ticketClerkConditionVariableNameLength[myIndex], ticketClerkLockName[myIndex], ticketClerkLockNameLength[myIndex]);
		finishedAgent(ticketClerkLockName[myIndex], ticketClerkLockNameLength[myIndex]);
		
		/*Printing("TicketClerk %i ticketClerkState == %i\n", ConsoleOutput, myIndex, GetMonitor(ticketClerkStateName, ticketClerkStateNameLength, myIndex));*/
		if(GetMonitor(ticketClerkStateName, ticketClerkStateNameLength, myIndex) != 0){
			/*STEP 2: TicketClerk-Customer, Tells Customer the total, and waits for the response (number of tickets)*/
			
			/*TODO: Check if customer can make a purchase?*/
			Printing("TicketClerk %i has an order for %i \0", ConsoleOutput, myIndex, GetMonitor(ticketClerkNumToSellName, ticketClerkNumToSellNameLength, myIndex));
			Printing("and the cost is %i.\n", ConsoleOutput,GetMonitor(ticketClerkNumToSellName, ticketClerkNumToSellNameLength, myIndex)*12,0);
			Signal(ticketClerkConditionVariableName[myIndex], ticketClerkConditionVariableNameLength[myIndex],ticketClerkLockName[myIndex], ticketClerkLockNameLength[myIndex]);
			Wait(ticketClerkConditionVariableName[myIndex], ticketClerkConditionVariableNameLength[myIndex], ticketClerkLockName[myIndex], ticketClerkLockNameLength[myIndex]);
			finishedAgent(ticketClerkLockName[myIndex], ticketClerkLockNameLength[myIndex]);
			
			/*STEP 3: TicketClerk-Customer, Takes cash from customer, puts in register.*/
			Printing("TicketClerk %i takes cash, puts in register.\n", ConsoleOutput,myIndex,0);
			
			tmp = GetMonitor(ticketClerkNumToSellName, ticketClerkNumToSellNameLength, myIndex);
			SetMonitor(ticketClerkRegisterName, ticketClerkRegisterNameLength, GetMonitor(ticketClerkRegisterName, ticketClerkRegisterNameLength, myIndex) + tmp * 12,myIndex);
			
			/*ticketClerkRegister[myIndex] += tmp * 12;*/
			
			SetMonitor(ticketClerkNumToSellName, ticketClerkNumToSellNameLength, 0, myIndex);
			/*ticketClerkNumToSell[myIndex] = 0; Resets to 0 inbetween transactions.*/
			

			Signal(ticketClerkConditionVariableName[myIndex], ticketClerkConditionVariableNameLength[myIndex], ticketClerkLockName[myIndex], ticketClerkLockNameLength[myIndex]);

			Wait(ticketClerkConditionVariableName[myIndex], ticketClerkConditionVariableNameLength[myIndex], ticketClerkLockName[myIndex], ticketClerkLockNameLength[myIndex]);
			finishedAgent(ticketClerkLockName[myIndex], ticketClerkLockNameLength[myIndex]);
			
		}
	

		
		
		/*printf("\tTC%i: i have risen\n", myIndex);*/
		/*Printing("TC%i to acquire lock %i\n", ConsoleOutput, myIndex, ticketClerkBreakLock[myIndex]);*/
		AcquireLock(ticketClerkBreakLockName[myIndex], ticketClerkBreakLockNameLength[myIndex]);
		
		
		ReleaseLock(ticketClerkLockName[myIndex], ticketClerkLockNameLength[myIndex]);

		if(GetMonitor(ticketClerkBreakName, ticketClerkBreakNameLength,myIndex) == 1){ /* i should go on break */
		
			/*printf("\tTC%i: trying to acquire the ticket clerk line lock, and i have the ticket clerk break lock\n", myIndex);*/
			/*AcquireLock(ticketClerkLineLock);*/
			/*printf("\tTC%i: ticket clerk line lock acquired\n", myIndex);*/
			/*ticketClerkLineCount[myIndex] = 0;*/
			/*Broadcast(ticketClerkLineConditionVariable[myIndex]ticketClerkLineLock);*/ /* signal to everyone in my line. need to acquire first???? MM: Yeah...Id say acquire.*/
			/*ReleaseLock(ticketClerkLineLock);*/
			/*printf("\tTC%i: ticket clerk line lock released\n", myIndex);*/
			Printing("TicketClerk %i is going on break.\n", ConsoleOutput, myIndex, 0);
			Wait(ticketClerkBreakConditionVariableName[myIndex], ticketClerkBreakConditionVariableNameLength[myIndex], ticketClerkBreakLockName[myIndex], ticketClerkBreakLockNameLength[myIndex]); /* wait until I am off break */
			finishedAgent(ticketClerkBreakLockName[myIndex], ticketClerkBreakLockNameLength[myIndex]);
			Printing("TicketClerk %i is coming off break.\n", ConsoleOutput, myIndex, 0);
		}
		

		ReleaseLock(ticketClerkBreakLockName[myIndex], ticketClerkBreakLockNameLength[myIndex]);
	}
	
}


int main(){

ticketClerk();

Exit(1);
}
